package com.example.system.service.exam;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.core.constants.Constants;
import com.example.common.core.enums.ResultCode;
import com.example.security.exception.ServiceException;
import com.example.system.domain.exam.Exam;
import com.example.system.domain.exam.ExamQuestion;
import com.example.system.domain.exam.dto.ExamAddDTO;
import com.example.system.domain.exam.dto.ExamEditDTO;
import com.example.system.domain.exam.dto.ExamQueryDTO;
import com.example.system.domain.exam.dto.ExamQuestionAddDTO;
import com.example.system.domain.exam.vo.ExamDetailVO;
import com.example.system.domain.exam.vo.ExamVO;
import com.example.system.domain.question.Question;
import com.example.system.domain.question.vo.QuestionVO;
import com.example.system.manager.ExamCacheManager;
import com.example.system.mapper.exam.ExamMapper;
import com.example.system.mapper.exam.ExamQuestionMapper;
import com.example.system.mapper.question.QuestionMapper;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author 23050
 * @version 1.0
 * @description: TODO
 * @date 2025/2/22 21:12
 */
@Service
public class ExamServiceImpl
        extends ServiceImpl<ExamQuestionMapper,ExamQuestion>
        implements ExamService{

    @Resource
    private ExamMapper examMapper;

    @Resource
    private QuestionMapper questionMapper;

    @Resource
    private ExamQuestionMapper examQuestionMapper;

    @Resource
    private  ExamCacheManager examCacheManager;

    //获取竞赛列表
    @Override
    public List<ExamVO> list(ExamQueryDTO examQueryDTO) {
        PageHelper.startPage(examQueryDTO.getPageNum(),examQueryDTO.getPageSize());
        return examMapper.selectExamList(examQueryDTO);
    }

    //添加竞赛
    @Override
    public String add(ExamAddDTO examAddDTO) {
        //检查参数
        checkExamSaveParams(examAddDTO,null);

        Exam exam = new Exam();
        BeanUtil.copyProperties(examAddDTO,exam);
        int ret = examMapper.insert(exam);
        if (ret<0){
            throw new ServiceException(ResultCode.FAILED);
        }
        return String.valueOf(exam.getExamId());
    }




    //竞赛中添加题目
    @Override
    public boolean questionAdd(ExamQuestionAddDTO examQuestionAddDTO) {

        //判断竞赛是否存在
        Exam exam = getExam(examQuestionAddDTO.getExamId());
        checkExam(exam);
        //判断新增的题目是否存在
        Set<Long> questionIdSet = examQuestionAddDTO.getQuestionIdSet();
        if (CollectionUtil.isEmpty(questionIdSet)){
            return true;
        }
        List<Question> questionList = questionMapper.selectBatchIds(questionIdSet);
        if (CollectionUtil.isEmpty(questionList)
                || questionList.size()< questionIdSet.size()){
            throw new ServiceException(ResultCode.EXAM_QUESTION_NOT_EXISTS);
        }
        //存数据库的时候要去重

        //存储数据库
        return saveExamQuestion(examQuestionAddDTO, questionIdSet);
    }

    //删除竞赛中的题目
    @Override
    public int questionDelete(Long examId, Long questionId) {
        //查看当前竞赛是否存在
        Exam exam = getExam(examId);
        checkExam(exam);
        int ret = examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId)
                .eq(ExamQuestion::getQuestionId, questionId));
        return ret;
    }



    //查询竞赛基本信息
    @Override
    public ExamDetailVO detail(Long examId) {
        ExamDetailVO examDetailVO = new ExamDetailVO();
        //判断竞赛是否存在
        Exam exam = getExam(examId);
        BeanUtil.copyProperties(exam,examDetailVO);

        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(new LambdaQueryWrapper<ExamQuestion>()
                .select(ExamQuestion::getQuestionId)
                .eq(ExamQuestion::getExamId, examId)
                .orderByAsc(ExamQuestion::getQuestionOrder));
        if (CollectionUtil.isEmpty(examQuestionList)){
            //竞赛题目为空，直接返回
            return examDetailVO;
        }

        //找到了竞赛中包含的题目id的集合
        List<Long> questionIdList = examQuestionList.stream().map(ExamQuestion::getQuestionId).toList();
        //在题目列表中查询对应的题目
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>()
                .select(Question::getQuestionId, Question::getTitle, Question::getDifficulty)
                .in(Question::getQuestionId, questionIdList));


        List<QuestionVO> questionVOList = BeanUtil.copyToList(questionList,QuestionVO.class);
        examDetailVO.setExamQuestionList(questionVOList);
        return examDetailVO;
    }

    //编辑竞赛详情
    @Override
    public int edit(ExamEditDTO examEditDTO) {
        //判断竞赛是否存在
        Exam exam = getExam(examEditDTO.getExamId());
        checkExam(exam);
        //判断竞赛参数是否合法
        checkExamSaveParams(examEditDTO,examEditDTO.getExamId());
        exam.setTitle(examEditDTO.getTitle());
        exam.setStartTime(examEditDTO.getStartTime());
        exam.setEndTime(examEditDTO.getEndTime());
        return examMapper.updateById(exam);
    }

    //删除竞赛
    @Override
    public int deleteExam(Long examId) {
        Exam exam = getExam(examId);
        checkExam(exam);
        //删除竞赛
        int ret = examMapper.deleteById(examId);
        //删除竞赛中的题目
        examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId));
        return ret;
    }

    //发布竞赛
    @Override
    public int publish(Long examId) {
        Exam exam = getExam(examId);//判断是否存在竞赛
        checkExam(exam);
        //已经完赛的竞赛不允许发布
        if (exam.getEndTime().isBefore(LocalDateTime.now())){
            throw new ServiceException(ResultCode.EXAM_IS_FINISH);
        }
        //判断竞赛中是否存在题目
        Long count = examQuestionMapper.selectCount(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId));
        if (count==null || count<=0){
            throw new ServiceException(ResultCode.EXAM_NOT_QUESTION);
        }
        exam.setStatus(Constants.PUBLICH_YES);
        int ret = examMapper.updateById(exam);
        if(ret>0){
            //发布竞赛后，将这个竞赛往redis中存储
            //exam:detail:examId:exam的详细信息        exam:timing:list:[examId]
           examCacheManager.addCache(exam);
        }
        return ret;
    }

    //撤销发布
    @Override
    public int cancelPublish(Long examId) {
        Exam exam = getExam(examId);//判断是否存在竞赛
        checkExam(exam);
        //已经完赛的竞赛不允许撤销发布
//        if (exam.getEndTime().isBefore(LocalDateTime.now())){
//            throw new ServiceException(ResultCode.EXAM_IS_FINISH);
//        }
        //插销发布
        exam.setStatus(Constants.PUBLICH_NO);
        int ret = examMapper.updateById(exam);
        if (ret>0){
            //从redis中删除这个竞赛
            examCacheManager.deleteCache(examId);
        }
        return ret;
    }


    //保存竞赛的题目
    private boolean saveExamQuestion(ExamQuestionAddDTO examQuestionAddDTO, Set<Long> questionIdSet) {
        //写入数据库
        int num = 1;
        List<ExamQuestion> examQuestionList = new ArrayList<>();
        for(Long questionId : questionIdSet){
            ExamQuestion examQuestion = new ExamQuestion();
            examQuestion.setQuestionId(questionId);
            examQuestion.setExamId(examQuestionAddDTO.getExamId());
            examQuestion.setQuestionOrder(num++);
            examQuestionList.add(examQuestion);
        }
        return saveBatch(examQuestionList);
    }

    //根据examId获取exam
    private Exam getExam(Long examId){
        //判断竞赛是否存在
        Exam exam = examMapper.selectById(examId);
        //不存在就不需要判断了
        if (exam == null){
            throw new ServiceException(ResultCode.EXAM_NOT_EXISTS);
        }
        return exam;
    }

    //判断参数是否合法
    private void checkExamSaveParams(ExamAddDTO examSaveDTO,Long examId) {
        List<Exam> exams = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .eq(Exam::getTitle, examSaveDTO.getTitle())
                .ne(examId!=null,Exam::getExamId,examId)
        );

        if (CollectionUtil.isNotEmpty(exams) && null == examId){
            throw new ServiceException(ResultCode.FAILED_ALREADY_EXISTS);
        }
        if (examSaveDTO.getStartTime().isBefore(LocalDateTime.now())){
            throw new ServiceException(ResultCode.EXAM_START_TIME_BEFORE_NOW);
        }
        if (examSaveDTO.getStartTime().isAfter(examSaveDTO.getEndTime())){
            throw new ServiceException(ResultCode.EXAM_START_TIME_AFTER_END_TIME);
        }
    }


    //判断竞赛是否能够操作
    private void checkExam(Exam exam) {
        //竞赛已经开始了，并且发布了，禁止操作
        if (exam.getStartTime().isBefore(LocalDateTime.now())
                &&exam.getEndTime().isAfter(LocalDateTime.now())
                && exam.getStatus()==1){
            throw new ServiceException(ResultCode.EXAM_STARTED);
        }
    }


}

